#include <dim-sum/bug.h>
#include <dim-sum/signal.h>
#include <asm/siginfo.h>
#include <asm/ptrace.h>
#include <asm/signal.h>
#include <dim-sum/syscall.h>
#include <asm/irqflags.h>
#include <uapi/asm/ucontex.h>
#include <dim-sum/mem.h>
#include <uapi/asm-generic/siginfo.h>
#include <uapi/asm-generic/errno-base.h>
#include <asm/exception.h>
#include <asm/uaccess.h>
#include <uapi/asm-generic/unistd.h>
#include <uapi/asm/ptrace.h>

#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn))

struct rt_sigframe
{
	struct siginfo *pinfo;
	void *puc;
	struct siginfo info;
	struct ucontext uc;
	unsigned int retcode[2];
};

asmlinkage int sys_rt_sigreturn(struct rt_sigframe *frame);

static inline void *get_sigframe(struct k_sigaction *ka, struct exception_spot *regs,
				 unsigned long framesize)
{
	unsigned long sp = regs->sp;

	/*
	 * No matter what happens, 'sp' must be word
	 * aligned otherwise nasty things could happen
	 */

	return (void *)((sp - framesize) & ~0xf);
}

int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
{
	int err = -EFAULT;;

	if (from->si_code < 0)
		return copy_to_user(to, from, sizeof(siginfo_t));

	/* If you change siginfo_t structure, please be sure
	   this code is fixed accordingly.
	   It should never copy any pad contained in the structure
	   to avoid security leaks, but must copy the generic
	   3 ints plus the relevant union member.  */
	err = __put_user(from->si_signo, &to->si_signo);
	err |= __put_user(from->si_errno, &to->si_errno);
	err |= __put_user((short)from->si_code, &to->si_code);
	/* First 32bits of unions are always present.  */
	err |= __put_user(from->si_pid, &to->si_pid);
	switch (from->si_code >> 16) {
	case __SI_FAULT >> 16:
		break;
	case __SI_CHLD >> 16:
		err |= __put_user(from->si_utime, &to->si_utime);
		err |= __put_user(from->si_stime, &to->si_stime);
		err |= __put_user(from->si_status, &to->si_status);
	default:
		err |= __put_user(from->si_uid, &to->si_uid);
		break;
	/* case __SI_RT: This is not generated by the kernel as of now.  */
	}
	return err;
}

static int
setup_sigcontext(struct sigcontext *sc, /*struct _fpstate *fpstate,*/
		 struct exception_spot *regs, unsigned long mask)
{
	int err = 0;
	copy_to_user(sc, regs, sizeof(*regs));
	return err;
}

static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
			   sigset_t *set, struct exception_spot *regs)
{
	struct rt_sigframe *frame;
	unsigned long retcode;
	int err = 0;
	frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe));

	err |= __put_user(&(frame->info), &frame->pinfo);
	err |= __put_user(&frame->uc, &frame->puc);
	err |= copy_siginfo_to_user(&frame->info, info);

	/* 把ucontext清零  */
	clear_user(&frame->uc, sizeof(struct ucontext));

	/**
	 * 保存内核栈
	 */
	err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
				regs, set->sig[0]);
	err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));

	/**
     * 设置信号处理完后，从用户态返回到内核态的指令。
    */
	if (ka->sa.sa_flags & SA_RESTORER) {
		retcode = (unsigned long)ka->sa.sa_restorer;
	} else {
		retcode = (unsigned long)current->sig->sig_ret_addr;
	}
	if (err) {
        goto segv_and_exit;
    }

	regs->a0 = sig;
	regs->sp = (unsigned long)frame;
	regs->sepc = (unsigned long)ka->sa.sa_handler;
	regs->ra = (unsigned long)retcode;
	return err;

segv_and_exit:
	if (sig == SIGSEGV) {
        ka->sa.sa_handler = SIG_DFL;
    }
	force_sigsegv(SIGSEGV, current);
    return err;
}

/*
 * OK, we're invoking a handler
 */	
static void
handle_signal(unsigned long sig, struct k_sigaction *ka,
	      siginfo_t *info, sigset_t *oldset, struct exception_spot * regs)
{
	setup_rt_frame(sig, ka, info, oldset, regs);

	if (ka->sa.sa_flags & SA_ONESHOT)
		ka->sa.sa_handler = SIG_DFL;

	if (!(ka->sa.sa_flags & SA_NODEFER)) {
		smp_lock_irq(&current->sigmask_lock);
		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
		sigaddset(&current->blocked,sig);
		recalc_sigpending(current);
		smp_unlock_irq(&current->sigmask_lock);
	}
}

int arch_do_signal(struct exception_spot *regs)
{
	struct k_sigaction *ka;
	siginfo_t info;
	sigset_t *oldset;
	struct ksignal ksig;

	if (!user_mode(regs)) {
		return 0;
	}

	oldset = &current->blocked;

	for (;;) {
		unsigned long signr;

		/**
		 * 收集signal相关信息。
		 */
		get_signal(&ksig);

		signr = ksig.sig;
		if (!signr) {
			break;
		}
		ka = &ksig.ka;
		/**
		 * 处理	需要忽略的信号
		 */
		if (ka->sa.sa_handler == SIG_IGN) {
			if (signr != SIGCHLD)
				continue;
			/**
			 * 暂未实现进程的父子关系,先注释掉
			 * 请梁老师检查
			 */
			/* Check for SIGCHLD: it's special.  */
			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
				/* nothing */;
			continue;
		}
		/**
		 * 处理 采用默认规则的信号
		 */
		if (ka->sa.sa_handler == SIG_DFL) {
			int exit_code = signr;

			/* Init gets no signals it doesn't want.  */
			if (current->pid == 1)
				continue;

			switch (signr) {
			case SIGCONT: case SIGCHLD: case SIGWINCH:
				continue;

			case SIGTSTP: case SIGTTIN: case SIGTTOU:
				// if (is_orphaned_pgrp(current->pgrp))
					continue;
				/* FALLTHRU */

			case SIGSTOP:
				current->state = TASK_STOPPED;
				current->exit_code = signr;
				/**
				 * 暂未实现进程的父子关系
				 * 请梁老师检查
				 */
				if (!(task_relation_parent(current)->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
					notify_parent(current, SIGCHLD);

				schedule();
				continue;

			case SIGQUIT: case SIGILL: case SIGTRAP:
			case SIGABRT: case SIGFPE: case SIGSEGV:
			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
				// if (do_coredump(signr, regs))
					exit_code |= 0x80;
				/* FALLTHRU */

			default:
				sigaddset(&current->pending.signal, signr);
				recalc_sigpending(current);
				current->flags |= TASKFLAG_SIGNALED;
				/**
				 * todo:目前exit实现不完整，资源回收不完全。
				 */
				sys_exit(exit_code);
			}
		}
		/**
		 * 执行预先设定的处理函数。
		 */
		/* Whee!  Actually deliver the signal.  */
		handle_signal(signr, ka, &info, oldset, regs);
		return 1;
	}
	return 0;
}
static int restore_sigcontext(struct exception_spot *regs, struct sigcontext *sc)
{
	// int i;
	// for (i = 0; i < 31; i++)
	BUG_ON(sizeof(*regs) != sizeof(*sc));
	copy_from_user(regs, sc, sizeof(*regs));
	// BUG();
	// copy_from_user(&regs->sp, &sc->sp, sizeof(__u64));
	// copy_from_user(&regs->sepc, &sc->pc, sizeof(__u64));
	// copy_from_user(&regs->sstatus, &sc->pstate, sizeof(__u64));
	return 0;
}
asmlinkage int sys_rt_sigreturn(struct rt_sigframe *frame)
{
	sigset_t set;

	struct exception_spot* regs = current_exception_spot();

	/*
	 * Since we stacked the signal on a word boundary,
	 * then 'sp' should be word aligned here.  If it's
	 * not, then the user is trying to mess with us.
	 */
	if (regs->sp & 0xf)
		goto badframe;

	if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
		goto badframe;
	if (copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
		goto badframe;

	sigdelsetmask(&set, ~_BLOCKABLE);
	smp_lock_irq(&current->sigmask_lock);
	current->blocked = set;
	recalc_sigpending(current);
	smp_unlock_irq(&current->sigmask_lock);

	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
		goto badframe;

	return regs->a0;

badframe:
	force_sig(SIGSEGV, current);
	return 0;
}

/**
 * 在中断、异常返回时处理系统通知
 */
void handle_system_notify(struct exception_spot *regs,
				 unsigned long flags)
{
	unsigned long thread_flags;

	if (flags == 0)
		thread_flags = current->flags;
	else
		thread_flags = flags;
	/**
	 * 目前只处理通知相关的，本来调度、信号也应该纳入这里一起处理
	 * 但它们已经在exception_tail函数中被处理了
	 */
	do {
		// local_daif_restore(DAIF_PROCCTX);

		if (thread_flags & _TIF_NOTIFY_RESUME) {
				clear_thread_flag(current, TIF_NOTIFY_RESUME);
				rseq_handle_notify_resume(NULL, regs);
		}

		// local_daif_mask();
		thread_flags = READ_ONCE(current->flags);
	} while (thread_flags & (_TIF_NOTIFY_RESUME));
}

int arch_sigretcode_page(void* __user addr, size_t size)
{
	extern char __kernel_rt_sigreturn;
	extern char __kernel_rt_sigreturn_end;

	char* codestart = &__kernel_rt_sigreturn;
	char* codeend = &__kernel_rt_sigreturn_end;
	size_t codesz;
	if (!codestart || !codeend || (codeend <= codestart))
		return -EINVAL;
	
	codesz = codeend - codestart;
	if (codesz < 1 || codesz > size)
		return -EINVAL;

	copy_to_user(addr, codestart, codesz);
	return 0;
}